# Load packages
library(ggplot2)
library(dplyr)
library(tidyr)
library(tidyverse)
library(plotly)
# Read datasets/confirmed_cases_worldwide.csv into confirmed_cases_worldwide
coronavirus <- read_csv("./data/coronavirus.csv")
Parsed with column specification:
cols(
  date = col_date(format = ""),
  province = col_logical(),
  country = col_character(),
  lat = col_double(),
  long = col_double(),
  type = col_character(),
  cases = col_double()
)
45800 parsing failures.
  row      col           expected  actual                     file
37001 province 1/0/T/F/TRUE/FALSE Alberta './data/coronavirus.csv'
37002 province 1/0/T/F/TRUE/FALSE Alberta './data/coronavirus.csv'
37003 province 1/0/T/F/TRUE/FALSE Alberta './data/coronavirus.csv'
37004 province 1/0/T/F/TRUE/FALSE Alberta './data/coronavirus.csv'
37005 province 1/0/T/F/TRUE/FALSE Alberta './data/coronavirus.csv'
..... ........ .................. ....... ........................
See problems(...) for more details.
head(coronavirus)
str(coronavirus)
tibble [157,000 × 7] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
 $ date    : Date[1:157000], format: "2020-01-22" "2020-01-23" "2020-01-24" ...
 $ province: logi [1:157000] NA NA NA NA NA NA ...
 $ country : chr [1:157000] "Afghanistan" "Afghanistan" "Afghanistan" "Afghanistan" ...
 $ lat     : num [1:157000] 33.9 33.9 33.9 33.9 33.9 ...
 $ long    : num [1:157000] 67.7 67.7 67.7 67.7 67.7 ...
 $ type    : chr [1:157000] "confirmed" "confirmed" "confirmed" "confirmed" ...
 $ cases   : num [1:157000] 0 0 0 0 0 0 0 0 0 0 ...
 - attr(*, "problems")= tibble [45,800 × 5] (S3: tbl_df/tbl/data.frame)
  ..$ row     : int [1:45800] 37001 37002 37003 37004 37005 37006 37007 37008 37009 37010 ...
  ..$ col     : chr [1:45800] "province" "province" "province" "province" ...
  ..$ expected: chr [1:45800] "1/0/T/F/TRUE/FALSE" "1/0/T/F/TRUE/FALSE" "1/0/T/F/TRUE/FALSE" "1/0/T/F/TRUE/FALSE" ...
  ..$ actual  : chr [1:45800] "Alberta" "Alberta" "Alberta" "Alberta" ...
  ..$ file    : chr [1:45800] "'./data/coronavirus.csv'" "'./data/coronavirus.csv'" "'./data/coronavirus.csv'" "'./data/coronavirus.csv'" ...
 - attr(*, "spec")=
  .. cols(
  ..   date = col_date(format = ""),
  ..   province = col_logical(),
  ..   country = col_character(),
  ..   lat = col_double(),
  ..   long = col_double(),
  ..   type = col_character(),
  ..   cases = col_double()
  .. )
# # See the result
bycountry <- coronavirus %>% 
  filter(type == "confirmed") %>%
  group_by(country) %>%
  summarise(total_cases = sum(cases)) %>%
  arrange(-total_cases)
`summarise()` ungrouping output (override with `.groups` argument)
bycountry


confirmed_cases = coronavirus %>% 
  group_by(date) %>%
  filter(type == "confirmed") %>%
  summarize(cases = sum(cases)) %>%
  mutate(cumsum = cumsum(cases))
`summarise()` ungrouping output (override with `.groups` argument)
# confirmed_cases_china = coronavirus %>%
#   group_by(date) %>%
#   filter(country == "China", type == "confirmed")%>% 
#   summarize(cases = sum(cases)) %>%
#   mutate(cumsum = cumsum(cases))
# confirmed_cases_china



(confirmed_cases)
NA
NA
NA
NA
NA
coronavirus %>% 
  filter(date == max(date)) %>%
  select(country, type, cases) %>%
  group_by(country, type) %>%
  summarise(total_cases = sum(cases)) %>%
  pivot_wider(names_from = type,
              values_from = total_cases) %>%
  arrange(-confirmed)
`summarise()` regrouping output by 'country' (override with `.groups` argument)
coronavirus %>% 
  group_by(type, date) %>%
  summarise(total_cases = sum(cases)) %>%
  pivot_wider(names_from = type, values_from = total_cases) %>%
  arrange(date) %>%
  mutate(active = confirmed - death - recovered) %>%
  mutate(active_total = cumsum(active),
                recovered_total = cumsum(recovered),
                death_total = cumsum(death)) %>%
  plot_ly(x = ~ date,
                  y = ~ active_total,
                  name = 'Active', 
                  fillcolor = '#1f77b4',
                  type = 'scatter',
                  mode = 'none', 
                  stackgroup = 'one') %>%
  add_trace(y = ~ death_total, 
             name = "Death",
             fillcolor = '#E41317') %>%
  add_trace(y = ~recovered_total, 
            name = 'Recovered', 
            fillcolor = 'forestgreen') %>%
  layout(title = "Distribution of Covid19 Cases Worldwide",
         legend = list(x = 0.1, y = 0.9),
         yaxis = list(title = "Number of Cases"),
         xaxis = list(title = "Source: Johns Hopkins University Center for Systems Science and Engineering"))
`summarise()` regrouping output by 'type' (override with `.groups` argument)
`arrange_()` is deprecated as of dplyr 0.7.0.
Please use `arrange()` instead.
See vignette('programming') for more help
This warning is displayed once every 8 hours.
Call `lifecycle::last_warnings()` to see where this warning was generated.
conf_df <- coronavirus %>% 
  filter(type == "confirmed") %>%
  group_by(country) %>%
  summarise(total_cases = sum(cases)) %>%
  arrange(-total_cases) %>%
  mutate(parents = "Confirmed") %>%
  ungroup() 
`summarise()` ungrouping output (override with `.groups` argument)
  
  plot_ly(data = conf_df,
          type= "treemap",
          values = ~total_cases,
          labels= ~ country,
          parents=  ~parents,
          domain = list(column=0),
          name = "Confirmed",
          textinfo="label+value+percent parent")
ggplot(confirmed_cases, aes(x = date, y = cum_cases)) +
  geom_line(aes(x = date, y = cum_cases)) +
  ylab("Cumulative confirmed cases")
Error in FUN(X[[i]], ...) : object 'cum_cases' not found

head(coronavirus)
coronavirus = tibble::rowid_to_column(coronavirus, "ID")
head(coronavirus)
# coronavirus = coronavirus %>%
#   group_by(ID) %>% 
#   mutate(cum_cases = cumsum(cases))
# coronavirus %>% head(70)
mutate(group_by(coronavirus, ID), cumsum = cumsum(cases))
# df <- data.frame(id = rep(1:3, each = 5),
#                  hour = rep(1:5, 3),
#                  value = sample(1:15))
# 
# mutate(group_by(df,id), cumsum=cumsum(value))
confirmed_cases_usa = coronavirus %>%
  group_by(date) %>%
  filter(country == "US", type == "confirmed")%>% 
  summarize(cases = sum(cases)) %>%
  mutate(cumsum = cumsum(cases))
`summarise()` ungrouping output (override with `.groups` argument)
confirmed_cases_usa
NA
plt_cum_confirmed_cases_usa <- ggplot(confirmed_cases_usa, aes(date, cumsum)) +
  geom_line() +
  ylab("Cumulative confirmed cases") 

# See the plot
plt_cum_confirmed_cases_usa

# Filter for USA, from Feb 15
usa_after_march1 <- confirmed_cases_usa %>%
  filter(date >= "2020-03-1")

# Using china_after_feb15, draw a line plot cum_cases vs. date
# Add a smooth trend line using linear regression, no error bars
ggplot(usa_after_march1, aes(date, cumsum)) +
  geom_line() +
  geom_smooth(method = "lm", formula = 'y ~ x', se = FALSE) +
  ylab("Cumulative confirmed cases")

confirmed_cases_china = coronavirus %>%
  group_by(date) %>%
  filter(country == "China", type == "confirmed")%>% 
  summarize(cases = sum(cases)) %>%
  mutate(cumsum = cumsum(cases))
`summarise()` ungrouping output (override with `.groups` argument)
confirmed_cases_china

confirmed_cases_china %>% 
  group_by(date) %>% 
  summarize(cases = sum(cases)) %>% 
  select(date, country, cases, cumsum)
`summarise()` ungrouping output (override with `.groups` argument)
Error: Can't subset columns that don't exist.
x Column `country` doesn't exist.
plt_cum_confirmed_cases_china <- ggplot(confirmed_cases_china, aes(date, cumsum)) +
  geom_line() +
  ylab("Cumulative confirmed cases") 

# See the plot
plt_cum_confirmed_cases_china

who_events <- tribble(
  ~ date, ~ event,
  "2020-01-30", "Global health emergency declared",
  "2020-03-11", "Pandemic declared",
  "2020-02-13", "China reporting change"
) %>%
  mutate(date = as.Date(date))

# Using who_events, add vertical dashed lines with an xintercept at date
# and text at date, labeled by event, and at 100000 on the y-axis
plt_cum_confirmed_cases_china + 
  geom_vline(aes(xintercept = date), data = who_events, linetype = "dashed") +
  geom_text(aes(x = date, label = event), data = who_events, y = 1e5)

# Filter for China, from Feb 15
china_after_feb15 <- confirmed_cases_china %>%
  filter(date >= "2020-02-15")

# Using china_after_feb15, draw a line plot cum_cases vs. date
# Add a smooth trend line using linear regression, no error bars
ggplot(china_after_feb15, aes(date, cumsum)) +
  geom_line() +
  geom_smooth(method = "lm", formula = 'y ~ x', se = FALSE) +
  ylab("Cumulative confirmed cases")

not_china = coronavirus %>%
  group_by(date) %>%
  filter(country != "China", type == "confirmed")%>% 
  summarize(cases = sum(cases)) %>%
  mutate(cumsum = cumsum(cases))
`summarise()` ungrouping output (override with `.groups` argument)
not_china

# not_china %>% 
#   group_by(date) %>% 
#   summarize(cases = sum(cases)) %>% 
#   select(date, country, cases, cumsum)


glimpse(not_china)
Rows: 200
Columns: 3
$ date   <date> 2020-01-22, 2020-01-23, 2020-01-24, 2020-01-25, 2020-01-26, 2020-01-27, 2…
$ cases  <dbl> 7, 4, 10, 7, 15, 7, 19, 10, 14, 32, 22, 10, 14, 20, 12, 12, 70, 30, 15, 84…
$ cumsum <dbl> 7, 11, 21, 28, 43, 50, 69, 79, 93, 125, 147, 157, 171, 191, 203, 215, 285,…
not_usa = coronavirus %>%
Warning messages:
1: In readChar(file, size, TRUE) : truncating string with embedded nuls
2: In readChar(file, size, TRUE) : truncating string with embedded nuls
3: In readChar(file, size, TRUE) : truncating string with embedded nuls
4: In readChar(file, size, TRUE) : truncating string with embedded nuls
5: In readChar(file, size, TRUE) : truncating string with embedded nuls
6: In readChar(file, size, TRUE) : truncating string with embedded nuls
7: In readChar(file, size, TRUE) : truncating string with embedded nuls
  group_by(date) %>%
  filter(country != "US", type == "confirmed")%>% 
  summarize(cases = sum(cases)) %>%
  mutate(cumsum = cumsum(cases))
`summarise()` ungrouping output (override with `.groups` argument)
not_usa
# Using not_usa, draw a line plot cum_cases vs. date
# Add a smooth trend line using linear regression, no error bars
plt_not_usa_trend_lin <- ggplot(not_usa, aes(date, cumsum)) +
  geom_line() +
  geom_smooth(method = "lm", formula = 'y ~ x', se = FALSE) +
  ylab("Cumulative confirmed cases")

# See the result
plt_not_usa_trend_lin 

not_china2 = coronavirus %>%
  group_by(date) %>%
  filter(country != "China", type == "confirmed")%>% 
  summarize(cases = sum(cases)) %>%
  mutate(cumsum = cumsum(cases))
`summarise()` ungrouping output (override with `.groups` argument)
not_china2

world_after_feb15 <- all_countries %>%
  filter(date >= "2020-02-15")
Error in eval(lhs, parent, parent) : object 'all_countries' not found
# Using not_china, draw a line plot cum_cases vs. date
# Add a smooth trend line using linear regression, no error bars
plt_not_china_trend_lin <- ggplot(not_china, aes(date, cumsum)) +
  geom_line() +
  geom_smooth(method = "lm", formula = 'y ~ x', se = FALSE) +
  ylab("Cumulative confirmed cases")

# See the result
plt_not_china_trend_lin 

plt_not_china_trend_lin + 
  scale_y_log10()
bycountry <- coronavirus %>% 
  mutate(date = as.Date(date))%>%
  filter(type == "confirmed") %>%
  group_by(country, date) %>%
  summarise(total_cases = sum(cases)) %>%
  arrange(-total_cases)
`summarise()` regrouping output by 'country' (override with `.groups` argument)

Filter by top 7 countries

target = c("Brazil", "India", "Mexico", "Peru", "Russia", "South Africa", "US")
top_7countries = bycountry %>% 
  filter(country %in% target) %>% 
  filter(total_cases > 0)

top_7countries
NA
plt_top_7countries = ggplot(top_7countries, aes(date, total_cases))  +
    geom_line(aes(group = country, color = country))+
    ylab("Cumulative confirmed cases")

plt_top_7countries

plt_top_7countries + 
  scale_y_log10()

ggplot(top_7countries, aes(x= country, y = total_cases))  +
    geom_boxplot(aes(color = country))

income_hist = clean %>% filter(top_7countries, country =='US') %>% 
  ggplot(., aes(x=total_cases)) +
  geom_histogram(bins=8) +
  theme_bw()
Error in eval(lhs, parent, parent) : object 'clean' not found
ui <- fluidPage(
  # CODE BELOW: Add a titlePanel with an appropriate title
  titlePanel("COVID-19"),
  # REPLACE CODE BELOW: with theme = shinythemes::shinytheme("<your theme>")
  theme = shinythemes::shinytheme("cerulean"),
  # shinythemes::themeSelector(),
  sidebarLayout(
    sidebarPanel(
      selectInput('country', 'Select Country', top_7countries$country, multiple = TRUE),
      dateRangeInput("date", "Select a Date Range", 
                     start = "2020-02-15",
                     end = "2020-08-15")
    ),
    mainPanel(
      tabsetPanel(
        tabPanel('Plot', plotly::plotlyOutput('plot_top_7countries')),
        tabPanel('Table', DT::DTOutput('table_top_7countries'))
      )
    )
  )
)
server <- function(input, output, session){
  # Function to plot trends in a name
  plot_trends <- function(){
     top_7countries %>%  
      filter(country == input$country, date >= "2020-02-15") %>% 
      ggplot(aes(x = date, y = total_cases)) +
      geom_line()
  }
  output$plot_top_7countries <- plotly::renderPlotly({
    validate(
    need(input$country != "", "Select a country and date range to get the app working")
    )
    plot_trends()
  })
  
  output$table_top_7countries <- DT::renderDT({
    top_7countries %>% 
      filter(country == input$country)
  })
}
shinyApp(ui = ui, server = server)

Listening on http://127.0.0.1:6288
NA
# Group by country, summarize to calculate total cases, find the top 7
coronavirus <- read_csv("./data/coronavirus.csv")
Parsed with column specification:
cols(
  date = col_date(format = ""),
  province = col_logical(),
  country = col_character(),
  lat = col_double(),
  long = col_double(),
  type = col_character(),
  cases = col_double()
)
45800 parsing failures.
  row      col           expected  actual                     file
37001 province 1/0/T/F/TRUE/FALSE Alberta './data/coronavirus.csv'
37002 province 1/0/T/F/TRUE/FALSE Alberta './data/coronavirus.csv'
37003 province 1/0/T/F/TRUE/FALSE Alberta './data/coronavirus.csv'
37004 province 1/0/T/F/TRUE/FALSE Alberta './data/coronavirus.csv'
37005 province 1/0/T/F/TRUE/FALSE Alberta './data/coronavirus.csv'
..... ........ .................. ....... ........................
See problems(...) for more details.
bycountry <- coronavirus %>% 
  mutate(date = as.Date(date))%>%
  filter(type == "confirmed") %>%
  group_by(country, date) %>%
  summarise(total_cases = sum(cases)) %>%
  arrange(-total_cases)
`summarise()` regrouping output by 'country' (override with `.groups` argument)
target = c("Brazil", "India", "Mexico", "Peru", "Russia", "South Africa", "US")
top_7countries = bycountry %>% 
  filter(country %in% target) %>% 
  filter(total_cases > 0)

top_7countries

ui <- fluidPage(
  # CODE BELOW: Add a titlePanel with an appropriate title
  titlePanel("COVID-19"),
  # REPLACE CODE BELOW: with theme = shinythemes::shinytheme("<your theme>")
  theme = shinythemes::shinytheme("superhero"),
  
  sidebarLayout(
    sidebarPanel(
      selectInput('country', 'Select Country', top_7countries$country, multiple = TRUE),
      dateRangeInput("date", "Select a Date Range", 
                     start = "2020-02-15",
                     end = "2020-08-15")
    ),
    mainPanel(
      tabsetPanel(
        tabPanel('Plot', plotly::plotlyOutput('plot_top_7countries')),
        tabPanel('Table', DT::DTOutput('table_top_7countries'))
      )
    )
  )
)
server <- function(input, output, session){
  # Function to plot trends in a name
  plot_trends <- function(){
     top_7countries %>%  
      filter(country == input$country, date >= "2020-02-15") %>% 
      ggplot(aes(x = date, y = total_cases)) +
      geom_line()
  }
  output$plot_top_7countries <- plotly::renderPlotly({
    validate(
    need(input$country != "", "Select a country and date range to get the app working")
    )
    plot_trends()
  })
  
  output$table_top_7countries <- DT::renderDT({
    top_7countries %>% 
      filter(country == input$country)
  })
}
shinyApp(ui = ui, server = server)

Listening on http://127.0.0.1:6288
NA
# Group by country, summarize to calculate total cases, find the top 7
owid_covid <- read_csv("./data/owid-covid-data.csv")
Parsed with column specification:
cols(
  .default = col_double(),
  iso_code = col_character(),
  continent = col_character(),
  location = col_character(),
  date = col_date(format = ""),
  new_tests = col_logical(),
  total_tests = col_logical(),
  total_tests_per_thousand = col_logical(),
  new_tests_per_thousand = col_logical(),
  new_tests_smoothed = col_logical(),
  new_tests_smoothed_per_thousand = col_logical(),
  tests_per_case = col_logical(),
  positive_rate = col_logical(),
  tests_units = col_logical()
)
See spec(...) for full column specifications.
108700 parsing failures.
 row                      col           expected        actual                         file
1169 new_tests                1/0/T/F/TRUE/FALSE 2.0           './data/owid-covid-data.csv'
1169 total_tests              1/0/T/F/TRUE/FALSE 2.0           './data/owid-covid-data.csv'
1169 total_tests_per_thousand 1/0/T/F/TRUE/FALSE 0.0           './data/owid-covid-data.csv'
1169 new_tests_per_thousand   1/0/T/F/TRUE/FALSE 0.0           './data/owid-covid-data.csv'
1169 tests_units              1/0/T/F/TRUE/FALSE people tested './data/owid-covid-data.csv'
.... ........................ .................. ............. ............................
See problems(...) for more details.
owid_bycountry = owid_covid %>% 
  group_by(location, date) %>%
  summarize(total_cases = sum(total_cases)) 
`summarise()` regrouping output by 'location' (override with `.groups` argument)
owid_bycountry

target = c("Brazil", "India", "Mexico", "Peru", "Russia", "South Africa", "United States")
top_7countries_OW = owid_bycountry %>% 
  group_by(location) %>% 
  filter(location %in% target) %>% 
  filter(total_cases > 0)

top_7countries_OW
ui <- fluidPage(
  # CODE BELOW: Add a titlePanel with an appropriate title
  titlePanel("COVID-19"),
  # REPLACE CODE BELOW: with theme = shinythemes::shinytheme("<your theme>")
  theme = shinythemes::shinytheme("cerulean"),
  # shinythemes::themeSelector(),
  sidebarLayout(
    sidebarPanel(
      selectInput('location', 'Select Country', top_7countries_OW$location),
  #     sliderInput("month", "Select Month:",
  #   min = 2, max = 8, value = 4, 
  # )
      selectInput('month','Select Month', top_7countries_OW$month, multiple = TRUE)
    ),
  
    mainPanel(
      tabsetPanel(
        tabPanel('Plot', plotly::plotlyOutput('plot_top_7countries_OW')),
        tabPanel('Table', DT::DTOutput('table_top_7countries_OW'))
      )
    )
  )
)
server <- function(input, output, session){
  # Function to plot trends in a name
  plot_trends <- function(){
     top_7countries_OW %>%  
      filter(location == input$location) %>% 
      filter(month == input$month) %>% 
      ggplot(aes(x = date, y = total_cases)) +
      geom_line()
  }
  output$plot_top_7countries_OW <- plotly::renderPlotly({
    validate(
    need(input$location != "", "Select a country to get the app working")
    )
    plot_trends()
  })
  
  output$table_top_7countries_OW <- DT::renderDT({
    top_7countries_OW %>% 
      filter(location == input$location)%>% 
      filter(month == input$month) %>% 
      select(location, date, total_cases)
  })
}
shinyApp(ui = ui, server = server)

Listening on http://127.0.0.1:6288
Error in : Problem with `filter()` input `..1`.
x Input `..1` must be of size 194 or 1, not size 0.
ℹ Input `..1` is `month == input$month`.
ℹ The error occured in group 1: location = "Italy".  124: <Anonymous>
NA
ui <- fluidPage(
  # set theme
  theme = shinythemes::shinytheme("cerulean"),
  # shinythemes::themeSelector(),
  
  ## attempt to create multi pages
  tags$head(
  tags$style(HTML("
          .navbar .navbar-header {float: right}
        ")) 
  ),
  
  navbarPage("WORLD", icon=icon('globe'),
    title="COVID-19 Worldwide by the Numbers",
    id="nav",
    position="fixed-top",
    collapsible=TRUE,
             br(),
             br(),
             br(),
             fluidRow(h1("World COVID-19 numbers by Month")),
          fluidRow(
  
  sidebarLayout(
    sidebarPanel(
      selectInput('location', 'Select Country', top_7countries_OW$location),
  #     sliderInput("month", "Select Month:",
  #   min = 2, max = 8, value = 4, 
  # )
      selectInput('month','Select Month', top_7countries_OW$month, multiple = TRUE)
    ),
  
    mainPanel(
      tabsetPanel(
        tabPanel('Plot', plotly::plotlyOutput('plot_top_7countries_OW')),
        tabPanel('Table', DT::DTOutput('table_top_7countries_OW'))
      )
    )
  )
)
), #end of first tabPanel
navbarMenu("EXPLORE", icon=icon('compass'),
                        br(),
                        br(),
                        br(),
                        fluidRow(h1("Renewable Energy Insights by Region")),
                        fluidRow( 
    sidebarLayout(
    sidebarPanel(
      selectInput('location', 'Select Country', top_7countries_OW$location),
      sliderInput("month", "Select Month:",
    min = 2, max = 8, value = 4,
  ),
    #   selectInput('month','Select Month', top_7countries_OW$month, multiple = TRUE)
    # ),
  
    mainPanel(
      tabsetPanel(
        tabPanel('Plot', plotly::plotlyOutput('plot_top_7countries_OW')),
        tabPanel('Table', DT::DTOutput('table_top_7countries_OW'))
      )
    )
  )
)
           
)
)
)
Error in buildTabset(tabs, "nav navbar-nav", NULL, id, selected) : 
  Tabs should all be unnamed arguments, but some are named: icon
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKCmBgYHtyfQojIExvYWQgcGFja2FnZXMKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShwbG90bHkpCgpgYGAKCmBgYHtyfQojIFJlYWQgZGF0YXNldHMvY29uZmlybWVkX2Nhc2VzX3dvcmxkd2lkZS5jc3YgaW50byBjb25maXJtZWRfY2FzZXNfd29ybGR3aWRlCmNvcm9uYXZpcnVzIDwtIHJlYWRfY3N2KCIuL2RhdGEvY29yb25hdmlydXMuY3N2IikKCmhlYWQoY29yb25hdmlydXMpCnN0cihjb3JvbmF2aXJ1cykKCiMgIyBTZWUgdGhlIHJlc3VsdApieWNvdW50cnkgPC0gY29yb25hdmlydXMgJT4lIAogIGZpbHRlcih0eXBlID09ICJjb25maXJtZWQiKSAlPiUKICBncm91cF9ieShjb3VudHJ5KSAlPiUKICBzdW1tYXJpc2UodG90YWxfY2FzZXMgPSBzdW0oY2FzZXMpKSAlPiUKICBhcnJhbmdlKC10b3RhbF9jYXNlcykKCmJ5Y291bnRyeQoKCmNvbmZpcm1lZF9jYXNlcyA9IGNvcm9uYXZpcnVzICU+JSAKICBncm91cF9ieShkYXRlKSAlPiUKICBmaWx0ZXIodHlwZSA9PSAiY29uZmlybWVkIikgJT4lCiAgc3VtbWFyaXplKGNhc2VzID0gc3VtKGNhc2VzKSkgJT4lCiAgbXV0YXRlKGN1bXN1bSA9IGN1bXN1bShjYXNlcykpCgojIGNvbmZpcm1lZF9jYXNlc19jaGluYSA9IGNvcm9uYXZpcnVzICU+JQojICAgZ3JvdXBfYnkoZGF0ZSkgJT4lCiMgICBmaWx0ZXIoY291bnRyeSA9PSAiQ2hpbmEiLCB0eXBlID09ICJjb25maXJtZWQiKSU+JSAKIyAgIHN1bW1hcml6ZShjYXNlcyA9IHN1bShjYXNlcykpICU+JQojICAgbXV0YXRlKGN1bXN1bSA9IGN1bXN1bShjYXNlcykpCiMgY29uZmlybWVkX2Nhc2VzX2NoaW5hCgoKCihjb25maXJtZWRfY2FzZXMpCgoKCgoKYGBgCgoKYGBge3J9CmNvcm9uYXZpcnVzICU+JSAKICBmaWx0ZXIoZGF0ZSA9PSBtYXgoZGF0ZSkpICU+JQogIHNlbGVjdChjb3VudHJ5LCB0eXBlLCBjYXNlcykgJT4lCiAgZ3JvdXBfYnkoY291bnRyeSwgdHlwZSkgJT4lCiAgc3VtbWFyaXNlKHRvdGFsX2Nhc2VzID0gc3VtKGNhc2VzKSkgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHR5cGUsCiAgICAgICAgICAgICAgdmFsdWVzX2Zyb20gPSB0b3RhbF9jYXNlcykgJT4lCiAgYXJyYW5nZSgtY29uZmlybWVkKQpgYGAKCgpgYGB7cn0KY29yb25hdmlydXMgJT4lIAogIGdyb3VwX2J5KHR5cGUsIGRhdGUpICU+JQogIHN1bW1hcmlzZSh0b3RhbF9jYXNlcyA9IHN1bShjYXNlcykpICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSB0eXBlLCB2YWx1ZXNfZnJvbSA9IHRvdGFsX2Nhc2VzKSAlPiUKICBhcnJhbmdlKGRhdGUpICU+JQogIG11dGF0ZShhY3RpdmUgPSBjb25maXJtZWQgLSBkZWF0aCAtIHJlY292ZXJlZCkgJT4lCiAgbXV0YXRlKGFjdGl2ZV90b3RhbCA9IGN1bXN1bShhY3RpdmUpLAogICAgICAgICAgICAgICAgcmVjb3ZlcmVkX3RvdGFsID0gY3Vtc3VtKHJlY292ZXJlZCksCiAgICAgICAgICAgICAgICBkZWF0aF90b3RhbCA9IGN1bXN1bShkZWF0aCkpICU+JQogIHBsb3RfbHkoeCA9IH4gZGF0ZSwKICAgICAgICAgICAgICAgICAgeSA9IH4gYWN0aXZlX3RvdGFsLAogICAgICAgICAgICAgICAgICBuYW1lID0gJ0FjdGl2ZScsIAogICAgICAgICAgICAgICAgICBmaWxsY29sb3IgPSAnIzFmNzdiNCcsCiAgICAgICAgICAgICAgICAgIHR5cGUgPSAnc2NhdHRlcicsCiAgICAgICAgICAgICAgICAgIG1vZGUgPSAnbm9uZScsIAogICAgICAgICAgICAgICAgICBzdGFja2dyb3VwID0gJ29uZScpICU+JQogIGFkZF90cmFjZSh5ID0gfiBkZWF0aF90b3RhbCwgCiAgICAgICAgICAgICBuYW1lID0gIkRlYXRoIiwKICAgICAgICAgICAgIGZpbGxjb2xvciA9ICcjRTQxMzE3JykgJT4lCiAgYWRkX3RyYWNlKHkgPSB+cmVjb3ZlcmVkX3RvdGFsLCAKICAgICAgICAgICAgbmFtZSA9ICdSZWNvdmVyZWQnLCAKICAgICAgICAgICAgZmlsbGNvbG9yID0gJ2ZvcmVzdGdyZWVuJykgJT4lCiAgbGF5b3V0KHRpdGxlID0gIkRpc3RyaWJ1dGlvbiBvZiBDb3ZpZDE5IENhc2VzIFdvcmxkd2lkZSIsCiAgICAgICAgIGxlZ2VuZCA9IGxpc3QoeCA9IDAuMSwgeSA9IDAuOSksCiAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICJOdW1iZXIgb2YgQ2FzZXMiKSwKICAgICAgICAgeGF4aXMgPSBsaXN0KHRpdGxlID0gIlNvdXJjZTogSm9obnMgSG9wa2lucyBVbml2ZXJzaXR5IENlbnRlciBmb3IgU3lzdGVtcyBTY2llbmNlIGFuZCBFbmdpbmVlcmluZyIpKQpgYGAKCmBgYHtyfQpjb25mX2RmIDwtIGNvcm9uYXZpcnVzICU+JSAKICBmaWx0ZXIodHlwZSA9PSAiY29uZmlybWVkIikgJT4lCiAgZ3JvdXBfYnkoY291bnRyeSkgJT4lCiAgc3VtbWFyaXNlKHRvdGFsX2Nhc2VzID0gc3VtKGNhc2VzKSkgJT4lCiAgYXJyYW5nZSgtdG90YWxfY2FzZXMpICU+JQogIG11dGF0ZShwYXJlbnRzID0gIkNvbmZpcm1lZCIpICU+JQogIHVuZ3JvdXAoKSAKICAKICBwbG90X2x5KGRhdGEgPSBjb25mX2RmLAogICAgICAgICAgdHlwZT0gInRyZWVtYXAiLAogICAgICAgICAgdmFsdWVzID0gfnRvdGFsX2Nhc2VzLAogICAgICAgICAgbGFiZWxzPSB+IGNvdW50cnksCiAgICAgICAgICBwYXJlbnRzPSAgfnBhcmVudHMsCiAgICAgICAgICBkb21haW4gPSBsaXN0KGNvbHVtbj0wKSwKICAgICAgICAgIG5hbWUgPSAiQ29uZmlybWVkIiwKICAgICAgICAgIHRleHRpbmZvPSJsYWJlbCt2YWx1ZStwZXJjZW50IHBhcmVudCIpCmBgYAoKYGBge3J9CmdncGxvdChjb25maXJtZWRfY2FzZXMsIGFlcyh4ID0gZGF0ZSwgeSA9IGN1bV9jYXNlcykpICsKICBnZW9tX2xpbmUoYWVzKHggPSBkYXRlLCB5ID0gY3VtX2Nhc2VzKSkgKwogIHlsYWIoIkN1bXVsYXRpdmUgY29uZmlybWVkIGNhc2VzIikKYGBgCgpgYGB7cn0KaGVhZChjb3JvbmF2aXJ1cykKYGBgCmBgYHtyfQpjb3JvbmF2aXJ1cyA9IHRpYmJsZTo6cm93aWRfdG9fY29sdW1uKGNvcm9uYXZpcnVzLCAiSUQiKQpoZWFkKGNvcm9uYXZpcnVzKQpgYGAKCmBgYHtyfQojIGNvcm9uYXZpcnVzID0gY29yb25hdmlydXMgJT4lCiMgICBncm91cF9ieShJRCkgJT4lIAojICAgbXV0YXRlKGN1bV9jYXNlcyA9IGN1bXN1bShjYXNlcykpCiMgY29yb25hdmlydXMgJT4lIGhlYWQoNzApCgpgYGAKCgpgYGB7cn0KbXV0YXRlKGdyb3VwX2J5KGNvcm9uYXZpcnVzLCBJRCksIGN1bXN1bSA9IGN1bXN1bShjYXNlcykpCmBgYAoKCmBgYHtyfQojIGRmIDwtIGRhdGEuZnJhbWUoaWQgPSByZXAoMTozLCBlYWNoID0gNSksCiMgICAgICAgICAgICAgICAgICBob3VyID0gcmVwKDE6NSwgMyksCiMgICAgICAgICAgICAgICAgICB2YWx1ZSA9IHNhbXBsZSgxOjE1KSkKIyAKIyBtdXRhdGUoZ3JvdXBfYnkoZGYsaWQpLCBjdW1zdW09Y3Vtc3VtKHZhbHVlKSkKYGBgCgpgYGB7cn0KY29uZmlybWVkX2Nhc2VzX3VzYSA9IGNvcm9uYXZpcnVzICU+JQogIGdyb3VwX2J5KGRhdGUpICU+JQogIGZpbHRlcihjb3VudHJ5ID09ICJVUyIsIHR5cGUgPT0gImNvbmZpcm1lZCIpJT4lIAogIHN1bW1hcml6ZShjYXNlcyA9IHN1bShjYXNlcykpICU+JQogIG11dGF0ZShjdW1zdW0gPSBjdW1zdW0oY2FzZXMpKQpjb25maXJtZWRfY2FzZXNfdXNhCgpgYGAKCgpgYGB7cn0KcGx0X2N1bV9jb25maXJtZWRfY2FzZXNfdXNhIDwtIGdncGxvdChjb25maXJtZWRfY2FzZXNfdXNhLCBhZXMoZGF0ZSwgY3Vtc3VtKSkgKwogIGdlb21fbGluZSgpICsKICB5bGFiKCJDdW11bGF0aXZlIGNvbmZpcm1lZCBjYXNlcyIpIAoKIyBTZWUgdGhlIHBsb3QKcGx0X2N1bV9jb25maXJtZWRfY2FzZXNfdXNhCmBgYAoKYGBge3J9CiMgRmlsdGVyIGZvciBVU0EsIGZyb20gRmViIDE1CnVzYV9hZnRlcl9tYXJjaDEgPC0gY29uZmlybWVkX2Nhc2VzX3VzYSAlPiUKICBmaWx0ZXIoZGF0ZSA+PSAiMjAyMC0wMy0xIikKCiMgVXNpbmcgY2hpbmFfYWZ0ZXJfZmViMTUsIGRyYXcgYSBsaW5lIHBsb3QgY3VtX2Nhc2VzIHZzLiBkYXRlCiMgQWRkIGEgc21vb3RoIHRyZW5kIGxpbmUgdXNpbmcgbGluZWFyIHJlZ3Jlc3Npb24sIG5vIGVycm9yIGJhcnMKZ2dwbG90KHVzYV9hZnRlcl9tYXJjaDEsIGFlcyhkYXRlLCBjdW1zdW0pKSArCiAgZ2VvbV9saW5lKCkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIGZvcm11bGEgPSAneSB+IHgnLCBzZSA9IEZBTFNFKSArCiAgeWxhYigiQ3VtdWxhdGl2ZSBjb25maXJtZWQgY2FzZXMiKQpgYGAKCmBgYHtyfQpjb25maXJtZWRfY2FzZXNfY2hpbmEgPSBjb3JvbmF2aXJ1cyAlPiUKICBncm91cF9ieShkYXRlKSAlPiUKICBmaWx0ZXIoY291bnRyeSA9PSAiQ2hpbmEiLCB0eXBlID09ICJjb25maXJtZWQiKSU+JSAKICBzdW1tYXJpemUoY2FzZXMgPSBzdW0oY2FzZXMpKSAlPiUKICBtdXRhdGUoY3Vtc3VtID0gY3Vtc3VtKGNhc2VzKSkKY29uZmlybWVkX2Nhc2VzX2NoaW5hCgpjb25maXJtZWRfY2FzZXNfY2hpbmEgJT4lIAogIGdyb3VwX2J5KGRhdGUpICU+JSAKICBzdW1tYXJpemUoY2FzZXMgPSBzdW0oY2FzZXMpKSAlPiUgCiAgc2VsZWN0KGRhdGUsIGNvdW50cnksIGNhc2VzLCBjdW1zdW0pCiAgCgpnbGltcHNlKGNvbmZpcm1lZF9jYXNlc19jaGluYSkKYGBgCgpgYGB7cn0KcGx0X2N1bV9jb25maXJtZWRfY2FzZXNfY2hpbmEgPC0gZ2dwbG90KGNvbmZpcm1lZF9jYXNlc19jaGluYSwgYWVzKGRhdGUsIGN1bXN1bSkpICsKICBnZW9tX2xpbmUoKSArCiAgeWxhYigiQ3VtdWxhdGl2ZSBjb25maXJtZWQgY2FzZXMiKSAKCiMgU2VlIHRoZSBwbG90CnBsdF9jdW1fY29uZmlybWVkX2Nhc2VzX2NoaW5hCmBgYAoKYGBge3J9Cndob19ldmVudHMgPC0gdHJpYmJsZSgKICB+IGRhdGUsIH4gZXZlbnQsCiAgIjIwMjAtMDEtMzAiLCAiR2xvYmFsIGhlYWx0aCBlbWVyZ2VuY3kgZGVjbGFyZWQiLAogICIyMDIwLTAzLTExIiwgIlBhbmRlbWljIGRlY2xhcmVkIiwKICAiMjAyMC0wMi0xMyIsICJDaGluYSByZXBvcnRpbmcgY2hhbmdlIgopICU+JQogIG11dGF0ZShkYXRlID0gYXMuRGF0ZShkYXRlKSkKCiMgVXNpbmcgd2hvX2V2ZW50cywgYWRkIHZlcnRpY2FsIGRhc2hlZCBsaW5lcyB3aXRoIGFuIHhpbnRlcmNlcHQgYXQgZGF0ZQojIGFuZCB0ZXh0IGF0IGRhdGUsIGxhYmVsZWQgYnkgZXZlbnQsIGFuZCBhdCAxMDAwMDAgb24gdGhlIHktYXhpcwpwbHRfY3VtX2NvbmZpcm1lZF9jYXNlc19jaGluYSArIAogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQgPSBkYXRlKSwgZGF0YSA9IHdob19ldmVudHMsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX3RleHQoYWVzKHggPSBkYXRlLCBsYWJlbCA9IGV2ZW50KSwgZGF0YSA9IHdob19ldmVudHMsIHkgPSAxZTUpCgpgYGAKCmBgYHtyfQojIEZpbHRlciBmb3IgQ2hpbmEsIGZyb20gRmViIDE1CmNoaW5hX2FmdGVyX2ZlYjE1IDwtIGNvbmZpcm1lZF9jYXNlc19jaGluYSAlPiUKICBmaWx0ZXIoZGF0ZSA+PSAiMjAyMC0wMi0xNSIpCgojIFVzaW5nIGNoaW5hX2FmdGVyX2ZlYjE1LCBkcmF3IGEgbGluZSBwbG90IGN1bV9jYXNlcyB2cy4gZGF0ZQojIEFkZCBhIHNtb290aCB0cmVuZCBsaW5lIHVzaW5nIGxpbmVhciByZWdyZXNzaW9uLCBubyBlcnJvciBiYXJzCmdncGxvdChjaGluYV9hZnRlcl9mZWIxNSwgYWVzKGRhdGUsIGN1bXN1bSkpICsKICBnZW9tX2xpbmUoKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgZm9ybXVsYSA9ICd5IH4geCcsIHNlID0gRkFMU0UpICsKICB5bGFiKCJDdW11bGF0aXZlIGNvbmZpcm1lZCBjYXNlcyIpCmBgYAoKYGBge3J9Cm5vdF9jaGluYSA9IGNvcm9uYXZpcnVzICU+JQogIGdyb3VwX2J5KGRhdGUpICU+JQogIGZpbHRlcihjb3VudHJ5ICE9ICJDaGluYSIsIHR5cGUgPT0gImNvbmZpcm1lZCIpJT4lIAogIHN1bW1hcml6ZShjYXNlcyA9IHN1bShjYXNlcykpICU+JQogIG11dGF0ZShjdW1zdW0gPSBjdW1zdW0oY2FzZXMpKQpub3RfY2hpbmEKCiMgbm90X2NoaW5hICU+JSAKIyAgIGdyb3VwX2J5KGRhdGUpICU+JSAKIyAgIHN1bW1hcml6ZShjYXNlcyA9IHN1bShjYXNlcykpICU+JSAKIyAgIHNlbGVjdChkYXRlLCBjb3VudHJ5LCBjYXNlcywgY3Vtc3VtKQoKCmdsaW1wc2Uobm90X2NoaW5hKQpgYGAKCmBgYHtyfQpub3RfdXNhID0gY29yb25hdmlydXMgJT4lCiAgZ3JvdXBfYnkoZGF0ZSkgJT4lCiAgZmlsdGVyKGNvdW50cnkgIT0gIlVTIiwgdHlwZSA9PSAiY29uZmlybWVkIiklPiUgCiAgc3VtbWFyaXplKGNhc2VzID0gc3VtKGNhc2VzKSkgJT4lCiAgbXV0YXRlKGN1bXN1bSA9IGN1bXN1bShjYXNlcykpCm5vdF91c2EKYGBgCgpgYGB7cn0KIyBVc2luZyBub3RfdXNhLCBkcmF3IGEgbGluZSBwbG90IGN1bV9jYXNlcyB2cy4gZGF0ZQojIEFkZCBhIHNtb290aCB0cmVuZCBsaW5lIHVzaW5nIGxpbmVhciByZWdyZXNzaW9uLCBubyBlcnJvciBiYXJzCnBsdF9ub3RfdXNhX3RyZW5kX2xpbiA8LSBnZ3Bsb3Qobm90X3VzYSwgYWVzKGRhdGUsIGN1bXN1bSkpICsKICBnZW9tX2xpbmUoKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgZm9ybXVsYSA9ICd5IH4geCcsIHNlID0gRkFMU0UpICsKICB5bGFiKCJDdW11bGF0aXZlIGNvbmZpcm1lZCBjYXNlcyIpCgojIFNlZSB0aGUgcmVzdWx0CnBsdF9ub3RfdXNhX3RyZW5kX2xpbiAKYGBgCgpgYGB7cn0Kbm90X2NoaW5hMiA9IGNvcm9uYXZpcnVzICU+JQogIGdyb3VwX2J5KGRhdGUpICU+JQogIGZpbHRlcihjb3VudHJ5ICE9ICJDaGluYSIsIHR5cGUgPT0gImNvbmZpcm1lZCIpJT4lIAogIHN1bW1hcml6ZShjYXNlcyA9IHN1bShjYXNlcykpICU+JQogIG11dGF0ZShjdW1zdW0gPSBjdW1zdW0oY2FzZXMpKQpub3RfY2hpbmEyCmBgYAoKYGBge3J9Cgp3b3JsZF9hZnRlcl9mZWIxNSA8LSBhbGxfY291bnRyaWVzICU+JQogIGZpbHRlcihkYXRlID49ICIyMDIwLTAyLTE1IikKCgphbGxfY291bnRyaWVzX3RyZW5kX2xpbiA8LSBnZ3Bsb3Qod29ybGRfYWZ0ZXJfZmViMTUsIGFlcyh4ID0gZGF0ZSwgeSA9Y3Vtc3VtKSkgKwogIGdlb21fbGluZSgpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBmb3JtdWxhID0gJ3kgfiB4Jywgc2UgPSBGQUxTRSkgKwogIHlsYWIoIkN1bXVsYXRpdmUgY29uZmlybWVkIGNhc2VzIikKCgojIFNlZSB0aGUgcmVzdWx0CmFsbF9jb3VudHJpZXNfdHJlbmRfbGluIAoKYGBgCgoKCmBgYHtyfQojIFVzaW5nIG5vdF9jaGluYSwgZHJhdyBhIGxpbmUgcGxvdCBjdW1fY2FzZXMgdnMuIGRhdGUKIyBBZGQgYSBzbW9vdGggdHJlbmQgbGluZSB1c2luZyBsaW5lYXIgcmVncmVzc2lvbiwgbm8gZXJyb3IgYmFycwpwbHRfbm90X2NoaW5hX3RyZW5kX2xpbiA8LSBnZ3Bsb3Qobm90X2NoaW5hLCBhZXMoZGF0ZSwgY3Vtc3VtKSkgKwogIGdlb21fbGluZSgpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBmb3JtdWxhID0gJ3kgfiB4Jywgc2UgPSBGQUxTRSkgKwogIHlsYWIoIkN1bXVsYXRpdmUgY29uZmlybWVkIGNhc2VzIikKCiMgU2VlIHRoZSByZXN1bHQKcGx0X25vdF9jaGluYV90cmVuZF9saW4gCmBgYAoKYGBge3J9CnBsdF9ub3RfY2hpbmFfdHJlbmRfbGluICsgCiAgc2NhbGVfeV9sb2cxMCgpCmBgYAoKYGBge3J9CiMgR3JvdXAgYnkgY291bnRyeSwgc3VtbWFyaXplIHRvIGNhbGN1bGF0ZSB0b3RhbCBjYXNlcywgZmluZCB0aGUgdG9wIDcKY29yb25hdmlydXMgPC0gcmVhZF9jc3YoIi4vZGF0YS9jb3JvbmF2aXJ1cy5jc3YiKQoKYnljb3VudHJ5IDwtIGNvcm9uYXZpcnVzICU+JSAKICBtdXRhdGUoZGF0ZSA9IGFzLkRhdGUoZGF0ZSkpJT4lCiAgZmlsdGVyKHR5cGUgPT0gImNvbmZpcm1lZCIpICU+JQogIGdyb3VwX2J5KGNvdW50cnksIGRhdGUpICU+JQogIHN1bW1hcmlzZSh0b3RhbF9jYXNlcyA9IHN1bShjYXNlcykpICU+JQogIGFycmFuZ2UoLXRvdGFsX2Nhc2VzKQoKCmJ5Y291bnRyeQoKCgp0b3BfY291bnRyaWVzX2J5X3RvdGFsX2Nhc2VzX2RhdGUgPSBieWNvdW50cnkgJT4lIAogIGdyb3VwX2J5KGNvdW50cnkpICU+JQogIHRvcF9uKDcsIHRvdGFsX2Nhc2VzKQoKCgoKdG9wX2NvdW50cmllc19ieV90b3RhbF9jYXNlcyA8LSBieWNvdW50cnkgJT4lCiAgZ3JvdXBfYnkoY291bnRyeSkgJT4lCiAgc3VtbWFyaXplKHRvdGFsX2Nhc2VzID0gc3VtKHRvdGFsX2Nhc2VzKSkgJT4lCiAgdG9wX24oNywgdG90YWxfY2FzZXMpCgoKCiMgU2VlIHRoZSByZXN1bHQKdG9wX2NvdW50cmllc19ieV90b3RhbF9jYXNlcwoKYGBgCgpGaWx0ZXIgYnkgdG9wIDcgY291bnRyaWVzCmBgYHtyfQp0YXJnZXQgPSBjKCJCcmF6aWwiLCAiSW5kaWEiLCAiTWV4aWNvIiwgIlBlcnUiLCAiUnVzc2lhIiwgIlNvdXRoIEFmcmljYSIsICJVUyIpCnRvcF83Y291bnRyaWVzID0gYnljb3VudHJ5ICU+JSAKICBmaWx0ZXIoY291bnRyeSAlaW4lIHRhcmdldCkgJT4lIAogIGZpbHRlcih0b3RhbF9jYXNlcyA+IDApCgp0b3BfN2NvdW50cmllcwoKYGBgCgoKYGBge3J9CnBsdF90b3BfN2NvdW50cmllcyA9IGdncGxvdCh0b3BfN2NvdW50cmllcywgYWVzKGRhdGUsIHRvdGFsX2Nhc2VzKSkgICsKICAgIGdlb21fbGluZShhZXMoZ3JvdXAgPSBjb3VudHJ5LCBjb2xvciA9IGNvdW50cnkpKSsKICAgIHlsYWIoIkN1bXVsYXRpdmUgY29uZmlybWVkIGNhc2VzIikKCnBsdF90b3BfN2NvdW50cmllcwpgYGAKCmBgYHtyfQpwbHRfdG9wXzdjb3VudHJpZXMgKyAKICBzY2FsZV95X2xvZzEwKCkKYGBgCgpgYGB7cn0KZ2dwbG90KHRvcF83Y291bnRyaWVzLCBhZXMoeD0gY291bnRyeSwgeSA9IHRvdGFsX2Nhc2VzKSkgICsKICAgIGdlb21fYm94cGxvdChhZXMoY29sb3IgPSBjb3VudHJ5KSkKYGBgCgoKYGBge3J9CmluY29tZV9oaXN0ID0gY2xlYW4gJT4lIGZpbHRlcih0b3BfN2NvdW50cmllcywgY291bnRyeSA9PSdVUycpICU+JSAKICBnZ3Bsb3QoLiwgYWVzKHg9dG90YWxfY2FzZXMpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlucz04KSArCiAgdGhlbWVfYncoKQpgYGAKCgpgYGB7cn0KdWkgPC0gZmx1aWRQYWdlKAogICMgQ09ERSBCRUxPVzogQWRkIGEgdGl0bGVQYW5lbCB3aXRoIGFuIGFwcHJvcHJpYXRlIHRpdGxlCiAgdGl0bGVQYW5lbCgiQ09WSUQtMTkiKSwKICAjIFJFUExBQ0UgQ09ERSBCRUxPVzogd2l0aCB0aGVtZSA9IHNoaW55dGhlbWVzOjpzaGlueXRoZW1lKCI8eW91ciB0aGVtZT4iKQogIHRoZW1lID0gc2hpbnl0aGVtZXM6OnNoaW55dGhlbWUoImNlcnVsZWFuIiksCiAgIyBzaGlueXRoZW1lczo6dGhlbWVTZWxlY3RvcigpLAogIHNpZGViYXJMYXlvdXQoCiAgICBzaWRlYmFyUGFuZWwoCiAgICAgIHNlbGVjdElucHV0KCdjb3VudHJ5JywgJ1NlbGVjdCBDb3VudHJ5JywgdG9wXzdjb3VudHJpZXMkY291bnRyeSwgbXVsdGlwbGUgPSBUUlVFKSwKICAgICAgZGF0ZVJhbmdlSW5wdXQoImRhdGUiLCAiU2VsZWN0IGEgRGF0ZSBSYW5nZSIsIAogICAgICAgICAgICAgICAgICAgICBzdGFydCA9ICIyMDIwLTAyLTE1IiwKICAgICAgICAgICAgICAgICAgICAgZW5kID0gIjIwMjAtMDgtMTUiKQogICAgKSwKICAgIG1haW5QYW5lbCgKICAgICAgdGFic2V0UGFuZWwoCiAgICAgICAgdGFiUGFuZWwoJ1Bsb3QnLCBwbG90bHk6OnBsb3RseU91dHB1dCgncGxvdF90b3BfN2NvdW50cmllcycpKSwKICAgICAgICB0YWJQYW5lbCgnVGFibGUnLCBEVDo6RFRPdXRwdXQoJ3RhYmxlX3RvcF83Y291bnRyaWVzJykpCiAgICAgICkKICAgICkKICApCikKc2VydmVyIDwtIGZ1bmN0aW9uKGlucHV0LCBvdXRwdXQsIHNlc3Npb24pewogICMgRnVuY3Rpb24gdG8gcGxvdCB0cmVuZHMgaW4gYSBuYW1lCiAgcGxvdF90cmVuZHMgPC0gZnVuY3Rpb24oKXsKICAgICB0b3BfN2NvdW50cmllcyAlPiUgIAogICAgICBmaWx0ZXIoY291bnRyeSA9PSBpbnB1dCRjb3VudHJ5LCBkYXRlID49ICIyMDIwLTAyLTE1IikgJT4lIAogICAgICBnZ3Bsb3QoYWVzKHggPSBkYXRlLCB5ID0gdG90YWxfY2FzZXMpKSArCiAgICAgIGdlb21fbGluZSgpCiAgfQogIG91dHB1dCRwbG90X3RvcF83Y291bnRyaWVzIDwtIHBsb3RseTo6cmVuZGVyUGxvdGx5KHsKICAgIHZhbGlkYXRlKAogICAgbmVlZChpbnB1dCRjb3VudHJ5ICE9ICIiLCAiU2VsZWN0IGEgY291bnRyeSBhbmQgZGF0ZSByYW5nZSB0byBnZXQgdGhlIGFwcCB3b3JraW5nIikKICAgICkKICAgIHBsb3RfdHJlbmRzKCkKICB9KQogIAogIG91dHB1dCR0YWJsZV90b3BfN2NvdW50cmllcyA8LSBEVDo6cmVuZGVyRFQoewogICAgdG9wXzdjb3VudHJpZXMgJT4lIAogICAgICBmaWx0ZXIoY291bnRyeSA9PSBpbnB1dCRjb3VudHJ5KQogIH0pCn0Kc2hpbnlBcHAodWkgPSB1aSwgc2VydmVyID0gc2VydmVyKQoKYGBgCgoKYGBge3J9CiMgR3JvdXAgYnkgY291bnRyeSwgc3VtbWFyaXplIHRvIGNhbGN1bGF0ZSB0b3RhbCBjYXNlcywgZmluZCB0aGUgdG9wIDcKY29yb25hdmlydXMgPC0gcmVhZF9jc3YoIi4vZGF0YS9jb3JvbmF2aXJ1cy5jc3YiKQoKYnljb3VudHJ5IDwtIGNvcm9uYXZpcnVzICU+JSAKICBtdXRhdGUoZGF0ZSA9IGFzLkRhdGUoZGF0ZSkpJT4lCiAgZmlsdGVyKHR5cGUgPT0gImNvbmZpcm1lZCIpICU+JQogIGdyb3VwX2J5KGNvdW50cnksIGRhdGUpICU+JQogIHN1bW1hcmlzZSh0b3RhbF9jYXNlcyA9IHN1bShjYXNlcykpICU+JQogIGFycmFuZ2UoLXRvdGFsX2Nhc2VzKQoKdGFyZ2V0ID0gYygiQnJhemlsIiwgIkluZGlhIiwgIk1leGljbyIsICJQZXJ1IiwgIlJ1c3NpYSIsICJTb3V0aCBBZnJpY2EiLCAiVVMiKQp0b3BfN2NvdW50cmllcyA9IGJ5Y291bnRyeSAlPiUgCiAgZmlsdGVyKGNvdW50cnkgJWluJSB0YXJnZXQpICU+JSAKICBmaWx0ZXIodG90YWxfY2FzZXMgPiAwKQoKdG9wXzdjb3VudHJpZXMKCnVpIDwtIGZsdWlkUGFnZSgKICAjIENPREUgQkVMT1c6IEFkZCBhIHRpdGxlUGFuZWwgd2l0aCBhbiBhcHByb3ByaWF0ZSB0aXRsZQogIHRpdGxlUGFuZWwoIkNPVklELTE5IiksCiAgIyBSRVBMQUNFIENPREUgQkVMT1c6IHdpdGggdGhlbWUgPSBzaGlueXRoZW1lczo6c2hpbnl0aGVtZSgiPHlvdXIgdGhlbWU+IikKICB0aGVtZSA9IHNoaW55dGhlbWVzOjpzaGlueXRoZW1lKCJzdXBlcmhlcm8iKSwKICAKICBzaWRlYmFyTGF5b3V0KAogICAgc2lkZWJhclBhbmVsKAogICAgICBzZWxlY3RJbnB1dCgnY291bnRyeScsICdTZWxlY3QgQ291bnRyeScsIHRvcF83Y291bnRyaWVzJGNvdW50cnksIG11bHRpcGxlID0gVFJVRSksCiAgICAgIGRhdGVSYW5nZUlucHV0KCJkYXRlIiwgIlNlbGVjdCBhIERhdGUgUmFuZ2UiLCAKICAgICAgICAgICAgICAgICAgICAgc3RhcnQgPSAiMjAyMC0wMi0xNSIsCiAgICAgICAgICAgICAgICAgICAgIGVuZCA9ICIyMDIwLTA4LTE1IikKICAgICksCiAgICBtYWluUGFuZWwoCiAgICAgIHRhYnNldFBhbmVsKAogICAgICAgIHRhYlBhbmVsKCdQbG90JywgcGxvdGx5OjpwbG90bHlPdXRwdXQoJ3Bsb3RfdG9wXzdjb3VudHJpZXMnKSksCiAgICAgICAgdGFiUGFuZWwoJ1RhYmxlJywgRFQ6OkRUT3V0cHV0KCd0YWJsZV90b3BfN2NvdW50cmllcycpKQogICAgICApCiAgICApCiAgKQopCnNlcnZlciA8LSBmdW5jdGlvbihpbnB1dCwgb3V0cHV0LCBzZXNzaW9uKXsKICAjIEZ1bmN0aW9uIHRvIHBsb3QgdHJlbmRzIGluIGEgbmFtZQogIHBsb3RfdHJlbmRzIDwtIGZ1bmN0aW9uKCl7CiAgICAgdG9wXzdjb3VudHJpZXMgJT4lICAKICAgICAgZmlsdGVyKGNvdW50cnkgPT0gaW5wdXQkY291bnRyeSwgZGF0ZSA+PSAiMjAyMC0wMi0xNSIpICU+JSAKICAgICAgZ2dwbG90KGFlcyh4ID0gZGF0ZSwgeSA9IHRvdGFsX2Nhc2VzKSkgKwogICAgICBnZW9tX2xpbmUoKQogIH0KICBvdXRwdXQkcGxvdF90b3BfN2NvdW50cmllcyA8LSBwbG90bHk6OnJlbmRlclBsb3RseSh7CiAgICB2YWxpZGF0ZSgKICAgIG5lZWQoaW5wdXQkY291bnRyeSAhPSAiIiwgIlNlbGVjdCBhIGNvdW50cnkgYW5kIGRhdGUgcmFuZ2UgdG8gZ2V0IHRoZSBhcHAgd29ya2luZyIpCiAgICApCiAgICBwbG90X3RyZW5kcygpCiAgfSkKICAKICBvdXRwdXQkdGFibGVfdG9wXzdjb3VudHJpZXMgPC0gRFQ6OnJlbmRlckRUKHsKICAgIHRvcF83Y291bnRyaWVzICU+JSAKICAgICAgZmlsdGVyKGNvdW50cnkgPT0gaW5wdXQkY291bnRyeSkKICB9KQp9CnNoaW55QXBwKHVpID0gdWksIHNlcnZlciA9IHNlcnZlcikKCmBgYAoKYGBge3J9CiMgR3JvdXAgYnkgY291bnRyeSwgc3VtbWFyaXplIHRvIGNhbGN1bGF0ZSB0b3RhbCBjYXNlcywgZmluZCB0aGUgdG9wIDcKb3dpZF9jb3ZpZCA8LSByZWFkX2NzdigiLi9kYXRhL293aWQtY292aWQtZGF0YS5jc3YiKQoKb3dpZF9ieWNvdW50cnkgPSBvd2lkX2NvdmlkICU+JSAKICBncm91cF9ieShsb2NhdGlvbiwgZGF0ZSkgJT4lCiAgc3VtbWFyaXplKHRvdGFsX2Nhc2VzID0gc3VtKHRvdGFsX2Nhc2VzKSkgCgpvd2lkX2J5Y291bnRyeQoKdGFyZ2V0ID0gYygiQnJhemlsIiwgIkluZGlhIiwgIk1leGljbyIsICJQZXJ1IiwgIlJ1c3NpYSIsICJTb3V0aCBBZnJpY2EiLCAiVW5pdGVkIFN0YXRlcyIpCnRvcF83Y291bnRyaWVzX09XID0gb3dpZF9ieWNvdW50cnkgJT4lIAogIGdyb3VwX2J5KGxvY2F0aW9uKSAlPiUgCiAgZmlsdGVyKGxvY2F0aW9uICVpbiUgdGFyZ2V0KSAlPiUgCiAgZmlsdGVyKHRvdGFsX2Nhc2VzID4gMCkKCnRvcF83Y291bnRyaWVzX09XCmBgYAoKCgpgYGB7cn0KIyB0b3BfY291bnRyaWVzX2J5X3RvdGFsX2Nhc2VzX2RhdGUgPSBvd2lkX2J5Y291bnRyeSAlPiUgCiMgICBncm91cF9ieShsb2NhdGlvbikgJT4lCiMgICBzdW1tYXJpemUodG90YWxfY2FzZXMgPSBzdW0odG90YWxfY2FzZXMpKSAlPiUKIyAgIHRvcF9uKDcsIHRvdGFsX2Nhc2VzKQojIAojIHRvcF9jb3VudHJpZXNfYnlfdG90YWxfY2FzZXNfZGF0ZQoKdG9wX2NvdW50cmllc19ieV90b3RhbF9jYXNlcyA8LSBvd2lkX2J5Y291bnRyeSAlPiUKICBncm91cF9ieShsb2NhdGlvbikgJT4lCiAgc3Vic2V0KGxvY2F0aW9uICE9ICJXb3JsZCIpICU+JQogIHN1bW1hcml6ZSh0b3RhbF9jYXNlcyA9IHN1bSh0b3RhbF9jYXNlcykpICU+JQogIHRvcF9uKDcsIHRvdGFsX2Nhc2VzKQoKdG9wX2NvdW50cmllc19ieV90b3RhbF9jYXNlcwoKdGFyZ2V0ID0gYygiQnJhemlsIiwgIkluZGlhIiwgIkl0YWx5IiwgIlNwYWluIiwgIlJ1c3NpYSIsICJVbml0ZWQgS2luZ2RvbSIsICJVbml0ZWQgU3RhdGVzIikKdG9wXzdjb3VudHJpZXNfT1cgPSBvd2lkX2J5Y291bnRyeSAlPiUgCiAgZ3JvdXBfYnkobG9jYXRpb24pICU+JSAKICBmaWx0ZXIobG9jYXRpb24gJWluJSB0YXJnZXQpICU+JSAKICBmaWx0ZXIodG90YWxfY2FzZXMgPiAwKQoKdG9wXzdjb3VudHJpZXNfT1cgCgoKCmxpYnJhcnkobHVicmlkYXRlKQoKdG9wXzdjb3VudHJpZXNfT1c9dG9wXzdjb3VudHJpZXNfT1cgJT4lIAogIG11dGF0ZShtb250aCA9IG1vbnRoKGRhdGUpLCBkYXkgPSBkYXkoZGF0ZSksIHllYXIgPSB5ZWFyKGRhdGUpKQoKb3dpZC1tZHkgPSBvd2lkX2J5Y291bnRyeSAlPiUgCiAgbXV0YXRlKG1vbnRoID0gbW9udGgoZGF0ZSksIGRheSA9IGRheShkYXRlKSwgeWVhciA9IHllYXIoZGF0ZSkpCgoKCgpgYGAKCgpgYGB7cn0KdWkgPC0gZmx1aWRQYWdlKAogICMgQ09ERSBCRUxPVzogQWRkIGEgdGl0bGVQYW5lbCB3aXRoIGFuIGFwcHJvcHJpYXRlIHRpdGxlCiAgdGl0bGVQYW5lbCgiQ09WSUQtMTkiKSwKICAjIFJFUExBQ0UgQ09ERSBCRUxPVzogd2l0aCB0aGVtZSA9IHNoaW55dGhlbWVzOjpzaGlueXRoZW1lKCI8eW91ciB0aGVtZT4iKQogIHRoZW1lID0gc2hpbnl0aGVtZXM6OnNoaW55dGhlbWUoImNlcnVsZWFuIiksCiAgIyBzaGlueXRoZW1lczo6dGhlbWVTZWxlY3RvcigpLAogIHNpZGViYXJMYXlvdXQoCiAgICBzaWRlYmFyUGFuZWwoCiAgICAgIHNlbGVjdElucHV0KCdsb2NhdGlvbicsICdTZWxlY3QgQ291bnRyeScsIHRvcF83Y291bnRyaWVzX09XJGxvY2F0aW9uKSwKICAjICAgICBzbGlkZXJJbnB1dCgibW9udGgiLCAiU2VsZWN0IE1vbnRoOiIsCiAgIyAgIG1pbiA9IDIsIG1heCA9IDgsIHZhbHVlID0gNCwgCiAgIyApCiAgICAgIHNlbGVjdElucHV0KCdtb250aCcsJ1NlbGVjdCBNb250aCcsIHRvcF83Y291bnRyaWVzX09XJG1vbnRoLCBtdWx0aXBsZSA9IFRSVUUpCiAgICApLAogIAogICAgbWFpblBhbmVsKAogICAgICB0YWJzZXRQYW5lbCgKICAgICAgICB0YWJQYW5lbCgnUGxvdCcsIHBsb3RseTo6cGxvdGx5T3V0cHV0KCdwbG90X3RvcF83Y291bnRyaWVzX09XJykpLAogICAgICAgIHRhYlBhbmVsKCdUYWJsZScsIERUOjpEVE91dHB1dCgndGFibGVfdG9wXzdjb3VudHJpZXNfT1cnKSkKICAgICAgKQogICAgKQogICkKKQpzZXJ2ZXIgPC0gZnVuY3Rpb24oaW5wdXQsIG91dHB1dCwgc2Vzc2lvbil7CiAgIyBGdW5jdGlvbiB0byBwbG90IHRyZW5kcyBpbiBhIG5hbWUKICBwbG90X3RyZW5kcyA8LSBmdW5jdGlvbigpewogICAgIHRvcF83Y291bnRyaWVzX09XICU+JSAgCiAgICAgIGZpbHRlcihsb2NhdGlvbiA9PSBpbnB1dCRsb2NhdGlvbikgJT4lIAogICAgICBmaWx0ZXIobW9udGggPT0gaW5wdXQkbW9udGgpICU+JSAKICAgICAgZ2dwbG90KGFlcyh4ID0gZGF0ZSwgeSA9IHRvdGFsX2Nhc2VzKSkgKwogICAgICBnZW9tX2xpbmUoKQogIH0KICBvdXRwdXQkcGxvdF90b3BfN2NvdW50cmllc19PVyA8LSBwbG90bHk6OnJlbmRlclBsb3RseSh7CiAgICB2YWxpZGF0ZSgKICAgIG5lZWQoaW5wdXQkbG9jYXRpb24gIT0gIiIsICJTZWxlY3QgYSBjb3VudHJ5IGFuZCBtb250aCB0byBnZXQgdGhlIGFwcCB3b3JraW5nIikKICAgICkKICAgIHBsb3RfdHJlbmRzKCkKICB9KQogIAogIG91dHB1dCR0YWJsZV90b3BfN2NvdW50cmllc19PVyA8LSBEVDo6cmVuZGVyRFQoewogICAgdG9wXzdjb3VudHJpZXNfT1cgJT4lIAogICAgICBmaWx0ZXIobG9jYXRpb24gPT0gaW5wdXQkbG9jYXRpb24pJT4lIAogICAgICBmaWx0ZXIobW9udGggPT0gaW5wdXQkbW9udGgpICU+JSAKICAgICAgc2VsZWN0KGxvY2F0aW9uLCBkYXRlLCB0b3RhbF9jYXNlcykKICB9KQp9CnNoaW55QXBwKHVpID0gdWksIHNlcnZlciA9IHNlcnZlcikKCmBgYAoKCmBgYHtyfQp1aSA8LSBmbHVpZFBhZ2UoCiAgIyBzZXQgdGhlbWUKICB0aGVtZSA9IHNoaW55dGhlbWVzOjpzaGlueXRoZW1lKCJjZXJ1bGVhbiIpLAogICMgc2hpbnl0aGVtZXM6OnRoZW1lU2VsZWN0b3IoKSwKICAKICAjIyBhdHRlbXB0IHRvIGNyZWF0ZSBtdWx0aSBwYWdlcwogIHRhZ3MkaGVhZCgKICB0YWdzJHN0eWxlKEhUTUwoIgogICAgICAgICAgLm5hdmJhciAubmF2YmFyLWhlYWRlciB7ZmxvYXQ6IHJpZ2h0fQogICAgICAgICIpKSAKICApLAogIAogIG5hdmJhclBhZ2UoIldPUkxEIiwgaWNvbj1pY29uKCdnbG9iZScpLAogICAgdGl0bGU9IkNPVklELTE5IFdvcmxkd2lkZSBieSB0aGUgTnVtYmVycyIsCiAgICBpZD0ibmF2IiwKICAgIHBvc2l0aW9uPSJmaXhlZC10b3AiLAogICAgY29sbGFwc2libGU9VFJVRSwKICAgICAgICAgICAgIGJyKCksCiAgICAgICAgICAgICBicigpLAogICAgICAgICAgICAgYnIoKSwKICAgICAgICAgICAgIGZsdWlkUm93KGgxKCJXb3JsZCBDT1ZJRC0xOSBudW1iZXJzIGJ5IE1vbnRoIikpLAogICAgICAgICAgZmx1aWRSb3coCiAgCiAgc2lkZWJhckxheW91dCgKICAgIHNpZGViYXJQYW5lbCgKICAgICAgc2VsZWN0SW5wdXQoJ2xvY2F0aW9uJywgJ1NlbGVjdCBDb3VudHJ5JywgdG9wXzdjb3VudHJpZXNfT1ckbG9jYXRpb24pLAogICMgICAgIHNsaWRlcklucHV0KCJtb250aCIsICJTZWxlY3QgTW9udGg6IiwKICAjICAgbWluID0gMiwgbWF4ID0gOCwgdmFsdWUgPSA0LCAKICAjICkKICAgICAgc2VsZWN0SW5wdXQoJ21vbnRoJywnU2VsZWN0IE1vbnRoJywgdG9wXzdjb3VudHJpZXNfT1ckbW9udGgsIG11bHRpcGxlID0gVFJVRSkKICAgICksCiAgCiAgICBtYWluUGFuZWwoCiAgICAgIHRhYnNldFBhbmVsKAogICAgICAgIHRhYlBhbmVsKCdQbG90JywgcGxvdGx5OjpwbG90bHlPdXRwdXQoJ3Bsb3RfdG9wXzdjb3VudHJpZXNfT1cnKSksCiAgICAgICAgdGFiUGFuZWwoJ1RhYmxlJywgRFQ6OkRUT3V0cHV0KCd0YWJsZV90b3BfN2NvdW50cmllc19PVycpKQogICAgICApCiAgICApCiAgKQopCiksICNlbmQgb2YgZmlyc3QgdGFiUGFuZWwKbmF2YmFyTWVudSgiRVhQTE9SRSIsIGljb249aWNvbignY29tcGFzcycpLAogICAgICAgICAgICAgICAgICAgICAgICBicigpLAogICAgICAgICAgICAgICAgICAgICAgICBicigpLAogICAgICAgICAgICAgICAgICAgICAgICBicigpLAogICAgICAgICAgICAgICAgICAgICAgICBmbHVpZFJvdyhoMSgiUmVuZXdhYmxlIEVuZXJneSBJbnNpZ2h0cyBieSBSZWdpb24iKSksCiAgICAgICAgICAgICAgICAgICAgICAgIGZsdWlkUm93KCAKICAgIHNpZGViYXJMYXlvdXQoCiAgICBzaWRlYmFyUGFuZWwoCiAgICAgIHNlbGVjdElucHV0KCdsb2NhdGlvbicsICdTZWxlY3QgQ291bnRyeScsIHRvcF83Y291bnRyaWVzX09XJGxvY2F0aW9uKSwKICAgICAgc2xpZGVySW5wdXQoIm1vbnRoIiwgIlNlbGVjdCBNb250aDoiLAogICAgbWluID0gMiwgbWF4ID0gOCwgdmFsdWUgPSA0LAogICksCiAgICAjICAgc2VsZWN0SW5wdXQoJ21vbnRoJywnU2VsZWN0IE1vbnRoJywgdG9wXzdjb3VudHJpZXNfT1ckbW9udGgsIG11bHRpcGxlID0gVFJVRSkKICAgICMgKSwKICAKICAgIG1haW5QYW5lbCgKICAgICAgdGFic2V0UGFuZWwoCiAgICAgICAgdGFiUGFuZWwoJ1Bsb3QnLCBwbG90bHk6OnBsb3RseU91dHB1dCgncGxvdF90b3BfN2NvdW50cmllc19PVycpKSwKICAgICAgICB0YWJQYW5lbCgnVGFibGUnLCBEVDo6RFRPdXRwdXQoJ3RhYmxlX3RvcF83Y291bnRyaWVzX09XJykpCiAgICAgICkKICAgICkKICApCikKICAgICAgICAgICAKKQopCikKKSAjIGVuZCBvZiBOYXYgYmFyCikgIyBlbmQgb2YgVUkKc2VydmVyIDwtIGZ1bmN0aW9uKGlucHV0LCBvdXRwdXQsIHNlc3Npb24pewogICMgRnVuY3Rpb24gdG8gcGxvdCB0cmVuZHMgaW4gYSBuYW1lCiAgcGxvdF90cmVuZHMgPC0gZnVuY3Rpb24oKXsKICAgICB0b3BfN2NvdW50cmllc19PVyAlPiUgIAogICAgICBmaWx0ZXIobG9jYXRpb24gPT0gaW5wdXQkbG9jYXRpb24pICU+JSAKICAgICAgZmlsdGVyKG1vbnRoID09IGlucHV0JG1vbnRoKSAlPiUgCiAgICAgIGdncGxvdChhZXMoeCA9IGRhdGUsIHkgPSB0b3RhbF9jYXNlcykpICsKICAgICAgZ2VvbV9saW5lKCkKICB9CiAgb3V0cHV0JHBsb3RfdG9wXzdjb3VudHJpZXNfT1cgPC0gcGxvdGx5OjpyZW5kZXJQbG90bHkoewogICAgdmFsaWRhdGUoCiAgICBuZWVkKGlucHV0JGxvY2F0aW9uICE9ICIiLCAiU2VsZWN0IGEgY291bnRyeSB0byBnZXQgdGhlIGFwcCB3b3JraW5nIikKICAgICkKICAgIHBsb3RfdHJlbmRzKCkKICB9KQogIAogIG91dHB1dCR0YWJsZV90b3BfN2NvdW50cmllc19PVyA8LSBEVDo6cmVuZGVyRFQoewogICAgdG9wXzdjb3VudHJpZXNfT1cgJT4lIAogICAgICBmaWx0ZXIobG9jYXRpb24gPT0gaW5wdXQkbG9jYXRpb24pJT4lIAogICAgICBmaWx0ZXIobW9udGggPT0gaW5wdXQkbW9udGgpICU+JSAKICAgICAgc2VsZWN0KGxvY2F0aW9uLCBkYXRlLCB0b3RhbF9jYXNlcykKICB9KQp9CnNoaW55QXBwKHVpID0gdWksIHNlcnZlciA9IHNlcnZlcikKCmBgYAoKCgoKCgo=